home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 49 / Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso / -serious- / misc / charmap / source / events.c < prev    next >
C/C++ Source or Header  |  1999-11-30  |  16KB  |  498 lines

  1. /***************************************************************
  2. ** Events.c: Prends en charge la gestion des événements uti-  **
  3. **           sateur. Écrit par T.Pierron                      **
  4. **           14-11-1999                                       **
  5. ***************************************************************/
  6.  
  7. /* All the necessary includes: */
  8. #include <Intuition/Intuition.H>                /* Std datatypes */
  9. #include <Intuition/IntuitionBase.H>        /* To access ActiveScreen */
  10. #include <Intuition/Screens.H>                /* Screen information */
  11. #include <Graphics/RastPort.H>                /* Rastport info */
  12. #include <Graphics/GfxBase.H>                    /* DefaultFont */
  13. #include <Graphics/Text.H>                        /* struct TextFont */
  14. #include <Libraries/Gadtools.H>                /* NewMenus and NewGadget */
  15. #include <Libraries/Commodities.H>            /* Commodity datatypes */
  16. #include <Libraries/Dos.H>                        /* CTRL/C signal */
  17. #include <Devices/InputEvent.H>                /* For raw keymap conversion */
  18.  
  19. #include "cmap.h"
  20. #define  CATCOMP_STRINGS                        /* We only need strings */
  21. #include "cmap_strings.h"                        /* Support of locale.library */
  22.  
  23. /* External variables: */
  24. extern struct IntuitionBase *IntuitionBase;
  25. extern struct GfxBase *GfxBase;
  26. extern struct Library *IconBase;
  27. extern struct Window *window;
  28. extern struct Screen *screen;
  29. extern struct NewMenu newmenu[],*checked,*checkset;
  30. extern struct NewWindow new_window;
  31. extern struct TextFont *font,*newfont;
  32. extern struct RastPort *RP;
  33. extern struct Gadget *gad;
  34. extern struct Menu *menu;
  35. extern WORD   xdeb,ydeb,xfin,yfin,X,Y;            /* ASCII Table position */
  36. extern UBYTE  MaxWid,Font_height,Char[];        /* Font information */
  37. extern ULONG  BoxTags[],sigwin;
  38. extern UBYTE  CharsetNum;
  39.  
  40.  
  41. struct TTextAttr *aslfont;                            /* Returned by the ASL font requester */
  42. struct MsgPort *broker_mp = NULL;                /* Commodity message port */
  43. CxObj  *broker, *filter;                            /* Commodity and hot-key */
  44. CxMsg  *msg;                                            /* To collect messages */
  45. UBYTE  *StrBuf;                                        /* Shortcut to string gadget's buffer */
  46. struct IntuiMessage message;
  47.  
  48. struct InputEvent ie = {0,IECLASS_RAWKEY};    /* Keyboard translation map: */
  49.  
  50. BOOL  IsDraw=0,PopWin=TRUE;                        /* State of the recessed box */
  51. WORD  NumChar;                                            /* Selected character number */
  52. ULONG cxsigflag=0;                                    /* Signal bits of the commo. */
  53.  
  54. struct NewBroker newbroker = {
  55.     NB_VERSION,
  56.     MSG_COMMONAME_STR,                /* String to identify this commo. */
  57.     MSG_DESCLINE1_STR,
  58.     MSG_DESCLINE2_STR,
  59.     NBU_UNIQUE | NBU_NOTIFY |        /* Don't want any new commodities starting with this name. */
  60.     COF_SHOW_HIDE,                        /* If someone tries it, let me know */
  61.     0, 0, 0, 0
  62. };
  63.  
  64. void Free_commodity();
  65.  
  66. /**** Initialize the message port of the commodity: ****/
  67. BOOL Init_commodity(int argc, char *argv[])
  68. {
  69.     UBYTE *hotkey, **ttypes;
  70.  
  71.     if(broker_mp = (void *) CreateMsgPort())
  72.     {
  73.         newbroker.nb_Port = broker_mp;
  74.         cxsigflag         = 1L << broker_mp->mp_SigBit;
  75.         ttypes            = (UBYTE **) ArgArrayInit(argc, argv);
  76.         newbroker.nb_Pri  = (BYTE)ArgInt(ttypes, "CX_PRIORITY", 0);
  77.         hotkey            = (UBYTE *) ArgString(ttypes, "HOTKEY", "rawkey lalt control c");
  78.  
  79.         /* Whould the user show immediatly the window ? */
  80.         if( strcasecmp(ArgString(ttypes, "CX_POPUP", Char), "NO")==0 ) PopWin=FALSE;
  81.  
  82.         if(broker = (void *) CxBroker(&newbroker, NULL))
  83.         {
  84.             /* HotKey() is an amiga.lib function that creates a filter, sender */
  85.             /* and translate CxObject and connects them to report a hot key    */
  86.             /* press and delete its input event. */
  87.             if(filter = (void *) HotKey(hotkey, broker_mp, EVT_HOTKEY))
  88.             {
  89.                 AttachCxObj(broker, filter);        /* Add a CxObject to another's personal list */
  90.  
  91.                 if(! CxObjError(filter))
  92.                     ActivateCxObj(broker, 1L);        /* All done! */
  93.             }
  94.         }
  95.         ArgArrayDone();  /* this amiga.lib function cleans up after ArgArrayInit() */
  96.     }
  97.  
  98.     return (broker && broker_mp);
  99. }
  100.  
  101. void Free_commodity()
  102. {
  103.     /* DeleteCxObjAll() is a commodities.library function that not only    **
  104.     ** deletes the CxObject pointed to in its argument, but deletes all of **
  105.     ** the CxObjects attached to it.                                       */
  106.     if(broker)
  107.     {
  108.         DeleteCxObjAll(broker);
  109.  
  110.         /* Empty the port of all CxMsgs */
  111.         while(msg = (CxMsg *)GetMsg(broker_mp))
  112.             ReplyMsg((struct Message *)msg);
  113.     }
  114.  
  115.     if(broker_mp) DeletePort(broker_mp);
  116. }
  117.  
  118. static WORD OldX=0,OldY=0,Xc=0,Yc=0;
  119. /**** Move the sunken box while dragging the mouse with LMB down: ****/
  120. void Handle_box()
  121. {
  122.     extern WORD txtpen, poppen, fillpen;
  123.     extern UBYTE CharWid[];
  124.     WORD sunken=FALSE;
  125.  
  126.     /* Center mouse position on top-left corner of the box: */
  127.     if(X<xdeb) X=0; else X -= (X-xdeb)%MaxWid;
  128.     if(Y<ydeb) Y=0; else Y -= (Y-ydeb)%Font_height;
  129.  
  130.     /* If it isn't already drawn... */
  131.     IsDraw=PRESSED;
  132.     if(X==OldX && Y==OldY) return;
  133.     BoxTags[2] = TAG_DONE;
  134.  
  135.     /* ...and inside area */
  136.     if(OldX>=xdeb && OldX<xfin && OldY>=ydeb && OldY<yfin)
  137.     {
  138.         DR:SetAPen(RP,sunken?fillpen : 0);
  139.         RectFill(RP,OldX+1,OldY+1,OldX+MaxWid-2,OldY+Font_height-2);
  140.         SetAPen(RP,sunken?poppen : txtpen);
  141.         Move(RP,OldX+(MaxWid-CharWid[NumChar]>>1),OldY+font->tf_Baseline+2);
  142.         *Char = (UBYTE) NumChar;
  143.         Text(RP,Char,1);
  144.  
  145.         DrawBevelBoxA(RP,OldX,OldY,MaxWid,Font_height,BoxTags);
  146.     }
  147.  
  148.     if(sunken) return; OldX=X; OldY=Y;
  149.  
  150.     if(X>=xdeb && X<xfin && Y>=ydeb && Y<yfin) {
  151.         BoxTags[2] = GTBB_Recessed;
  152.         NumChar = ((X-xdeb)/MaxWid<<3)+(Y-ydeb)/Font_height;
  153.         if(CharsetNum >1) NumChar+=32;
  154.         if(CharsetNum==3 && NumChar>127) NumChar+=160-128;
  155.         sunken=TRUE; Xc=X; Yc=Y; goto DR;
  156.     } else {
  157.         NumChar=-1;
  158.         IsDraw=OUTSIDE_AREA;
  159.     }
  160. }
  161.  
  162. /**** Move the box using the keyboard: ****/
  163. void Handle_keyboard(UWORD code)
  164. {
  165.     /* To prevent that keyboard doesn't disturb the mouse: */
  166.     if(IsDraw > 0 || code<76 || code>79) return;
  167.     if(Xc)
  168.     {
  169.         /* Rawkey code for arrow keys: */
  170.         switch(code)
  171.         {
  172.             case 76: Yc -= Font_height; break;
  173.             case 77: Yc += Font_height; break;
  174.             case 78: Xc += MaxWid;      break;
  175.             case 79: Xc -= MaxWid;      break;
  176.         }
  177.         /* Check if cursor overrun the map: */
  178.         if(Yc< ydeb) { Yc=yfin-Font_height; Xc-=MaxWid; }
  179.         if(Yc>=yfin) { Yc=ydeb; Xc+=MaxWid; }
  180.         if(Xc< xdeb) Xc=xfin-MaxWid;
  181.         if(Xc>=xfin) Xc=xdeb;
  182.  
  183.     } else {
  184.         /* If cursor hasn't been moved yet: */
  185.         Xc=xdeb; Yc=ydeb;
  186.     }
  187.     X=Xc; Y=Yc;
  188.     Handle_box();
  189.     /* To prevent mouse doesn't disturb the keyboard: */
  190.     IsDraw=KEYB_CONTROL;
  191. }
  192.  
  193. /**** Processes menus events: ****/
  194. void Handle_menu( LONG MenuID )
  195. {
  196.     extern struct EasyStruct Request;
  197.  
  198.     /** L'auteur présente ses plus plates excuses pour ce très ***
  199.     ***       mauvais exemple de programmation spaghetti.      **/
  200.     switch( MenuID )
  201.     {
  202.         case 11:    /* Look if the first item isn't already selected: */
  203.                     if(checked == &newmenu[1]) break;
  204.                     /* Take the font of the screen (Please, don't close it!): */
  205.                     font = screen->RastPort.Font; goto check;
  206.         case 12:    /* Ditto: */
  207.                     if(checked == &newmenu[2]) break;
  208.                     font = GfxBase->DefaultFont;
  209.         check:    /* Menus will be reallocated, change NewMenus struct. directly: */
  210.                     checked->nm_Flags &= ~CHECKED;
  211.                     checked = &newmenu[ MenuID-10 ];
  212.                     checked->nm_Flags |= CHECKED;
  213.                     /* Change the charset depending of the font: */
  214.                     Init_charset(font);
  215.                     MenuID = CharsetNum+140;
  216.                     goto charset;
  217.         REDOIT:    MenuID = 13;
  218.         case 13:    /* Open a ASL requester: */
  219.                     if( aslfont = (struct TTextAttr *) open_asl() )
  220.                     {
  221.                         if( newfont ) CloseFont(newfont);
  222.                         if( newfont=(void *)OpenDiskFont(aslfont) )
  223.                         {
  224.                             font = newfont;
  225.                             goto check;
  226.                         }
  227.                     }
  228.                     /* Cancel the menu selection (sorry, I don't want to use temporary variables) */
  229.                     ((struct MenuItem *)ItemAddress(menu,SHIFTMENU(0)+SHIFTITEM(checked-&newmenu[1])+SHIFTSUB(NOSUB)))->Flags |= CHECKED;
  230.                     ((struct MenuItem *)ItemAddress(menu,SHIFTMENU(0)+SHIFTITEM(2)+SHIFTSUB(NOSUB)))->Flags &= (~CHECKED);
  231.                     break;
  232.                     /* Changing the charset of ASCII table: */
  233.         case 141:if(checkset == &newmenu[6]) break; goto charset;
  234.         case 142:if(checkset == &newmenu[7]) break; goto charset;
  235.         case 143:if(checkset == &newmenu[8]) break;
  236.  
  237.         charset:    checkset->nm_Flags &= ~CHECKED;
  238.                     checkset   = &newmenu[ MenuID-141+6 ];
  239.                     CharsetNum = MenuID-140;
  240.                     checkset->nm_Flags |= CHECKED;
  241.                     new_window.Title = checkset->nm_Label;
  242.                     /* Now, we can reopen our window: */
  243.                     goto new_win;
  244.  
  245.         case 14:    /* Clear the text contained in the string gadget: */
  246.                     StrBuf[0]=0; RefreshGList(gad, window, NULL, 1);
  247.                     break;
  248.         case 15:    /* Jump to the next screen: */
  249.                     if( !screen->NextScreen ) break;
  250.                     screen = screen->NextScreen;
  251.                     if(checked == &newmenu[1]) font = screen->RastPort.Font;
  252.         new_win:    cleanup(NULL,-1);
  253.                     /* If init failed, try to see if we can changed the font again: */
  254.                     if( setup() ) goto REDOIT;
  255.                     /* Before to move the screen, wait all it's OK: */
  256.                     ScreenToFront(screen);
  257.                     break;
  258.         case 16:    EasyRequestArgs(window, &Request, 0, 0); break;
  259.         case 17: /* Iconify/Uniconify the window: */
  260.                     ZipWindow(window);
  261.                     break;
  262.         case 18:    cleanup(NULL,-1); return;
  263.         case 19:    cleanup(NULL,0);
  264.     }
  265.     if(window==NULL) cleanup(0,0);
  266. }
  267.  
  268. /**** Handle all messages comming from a commo: ****/
  269. void Handle_commo(void)
  270. {
  271.     ULONG msgid, msgtype;
  272.  
  273.     /* The signal is comming from a commodity: */
  274.     while(msg = (CxMsg *)GetMsg(broker_mp))
  275.     {
  276.         msgid = CxMsgID(msg);
  277.         msgtype = CxMsgType(msg);
  278.         ReplyMsg((struct Message *)msg);
  279.  
  280.         switch(msgtype)
  281.         {
  282.             case CXM_IEVENT:
  283.                 /* Display or move the window, in the front-most screen: */
  284.                 if(msgid == EVT_HOTKEY)
  285.                 {
  286.                     screen = IntuitionBase->ActiveScreen;
  287.                     /* If the window is already open, but not in the front-most screen, close it: */
  288.                     if(window)
  289.                         if(window->WScreen != screen) cleanup(NULL,-1);
  290.                         else {
  291.                             /* Activate and move it to front: */
  292.                             WindowToFront(window);
  293.                             ActivateWindow(window);
  294.                             /* If the window is iconified, uniconify it: */
  295.                             if(window->Height<=window->BorderTop) ZipWindow(window);
  296.                             break;
  297.                         }
  298.  
  299.                     /* The screen font can be changed: */
  300.                     if(checked == &newmenu[1]) font = screen->RastPort.Font;
  301.                     /* If something goes wrong, change the font: */
  302.                     if( setup() ) Handle_menu(13);
  303.                     ScreenToFront(screen);
  304.                 }
  305.                 break;
  306.             case CXM_COMMAND:
  307.                 switch(msgid)
  308.                 {
  309.                     case CXCMD_DISABLE:
  310.                         /* If user want to disable the commo, iconify the window: */
  311.                         if(window->Height>window->BorderTop) ZipWindow(window);
  312.                         ActivateCxObj(broker, 0L);
  313.                         break;
  314.                     case CXCMD_ENABLE:
  315.                         /* If user want to enable the commo, uniconify it: */
  316.                         if(window->Height<=window->BorderTop) ZipWindow(window);
  317.                         ActivateCxObj(broker, 1L);
  318.                         break;
  319.  
  320.                     case CXCMD_APPEAR:    if(window==NULL && setup())
  321.                                                     Handle_menu(13);                break;
  322.                     case CXCMD_DISAPPEAR:if(window) cleanup(NULL,-1);    break;
  323.                     case CXCMD_KILL:
  324.                     case CXCMD_UNIQUE:
  325.                         /* Commodities Exchange can be told not only to refuse to launch a   **
  326.                         ** commodity with a name already in use but also can notify the      **
  327.                         ** already running commodity that it happened.  It does this by      **
  328.                         ** sending a CXM_COMMAND with the ID set to CXMCMD_UNIQUE.  If the   **
  329.                         ** user tries to run a windowless commodity that is already running, **
  330.                         ** the user wants the commodity to shut down.                        */
  331.                         cleanup(0,0);
  332.                 }
  333.         }
  334.     }
  335. }
  336.  
  337. /**** Handle gadget messages ****/
  338. void Handle_gadget( struct Gadget *G )
  339. {
  340.     extern void *clipdev;
  341.     extern UBYTE GadDisable;
  342.  
  343.     /* If clipboard is unavailable: */
  344.     if(G->GadgetID<3 && !clipdev && !(clipdev=(void *)CBOpen(0))) {
  345.         OffGadget(G, window, NULL);
  346.         GadDisable |= 3;
  347.         return;
  348.     }
  349.  
  350.     switch(G->GadgetID)
  351.     {
  352.         case 1: /* Copy string into clipboard: */
  353.             CBWriteFTXT(clipdev, StrBuf);
  354.             break;
  355.         case 2: /* Read string from clipboard: */
  356.             if( CBQueryFTXT(clipdev) )
  357.             {
  358.                 CBReadCHRS(clipdev, StrBuf, sti(gad)->MaxChars);
  359.                 RefreshGList(gad, window, NULL, 1);
  360.             }
  361.             break;
  362.         case 3: /* Clear everything in the string gadget */
  363.             Handle_menu(14);
  364.             break;
  365.         case 4: /* Choose a different font */
  366.             Handle_menu(13);
  367.     }
  368. }
  369.  
  370. /**** Main loop, which collects and distributes all messages: ****/
  371. void handle_input(void)
  372. {
  373.     static UBYTE buffer[8];
  374.     UWORD  HelpWin=FALSE;
  375.     ULONG  sigrcvd;
  376.  
  377.     FOREVER {
  378. Deb:    sigrcvd = Wait(SIGBREAKF_CTRL_C | cxsigflag | sigwin);
  379.  
  380.         /* Look from where the signal has been launched: */
  381.         if(sigrcvd & SIGBREAKF_CTRL_C) cleanup(0,0);
  382.  
  383.         if(sigrcvd & cxsigflag) Handle_commo();
  384.  
  385.         if((sigrcvd & sigwin) == 0) continue;
  386.  
  387.         /* Use the new GadTools GT_GetIMsg() function to get input events */
  388.         while (msg = (void *) GT_GetIMsg(window->UserPort))
  389.         {
  390.             /* Copy entire message: */
  391.             CopyMem(msg,&message,sizeof(message));
  392.  
  393.             /* Is it a mouse button or a menu call? */
  394.             if( message.Code == MENUHOT && (IsDraw || (Y>=ydeb && Y<=yfin && X>=xdeb && X<=xfin)) &&
  395.                 window->Height>window->BorderTop)
  396.             {
  397.                 /* The right mouse button has been pressed over the ASCII table: */
  398.                 ((struct IntuiMessage *)msg)->Code=MENUCANCEL;
  399.                 message.Class=MOUSEBUTTONS;
  400.                 window->Flags |= RMBTRAP;
  401.             }
  402.  
  403.             /* Reply to the message */
  404.             GT_ReplyIMsg(msg);
  405.             X=message.MouseX; Y=message.MouseY;
  406.  
  407.             switch(message.Class)
  408.             {
  409.                 /* The close-window gad. simply quit: */
  410.                 case CLOSEWINDOW:    cleanup(NULL,0);
  411.                 case MOUSEBUTTONS:
  412.                     switch(message.Code)
  413.                     {
  414.                         /* Draw a recessed box below the mouse: */
  415.                         case SELECTDOWN: if(HelpWin==FALSE) Handle_box(); break;
  416.                         /* Clear the box and add the char. in string gadget: */
  417.                         case SELECTUP:
  418.                             if(IsDraw) {
  419.                                 INS:if(NumChar>=0 && IsDraw) {
  420.                                     struct StringInfo *st = sti(gad);;
  421.  
  422.                                     if(st->NumChars>=st->MaxChars-1) strcpy(StrBuf, StrBuf+1);
  423.  
  424.                                     strcat(st->Buffer,Char);
  425.                                     RefreshGList(gad, window, NULL, 1);
  426.                                     /* If char has been keyed in, don't clear the cursor: */
  427.                                     if(IsDraw==KEYB_CONTROL) break;
  428.                                 }
  429.                                 Xc=X; Yc=Y; CL:X=Y=0; Handle_box(); IsDraw=NOT_PRESSED;
  430.                             }
  431.                             break;
  432.                         /* Draw a little window and show information on the char.: */
  433.                         case MENUHOT:
  434.                             if(IsDraw) goto CL;
  435.                             else { 
  436.                                 Handle_box();
  437.                                 if(NumChar>=0) { HelpWin=TRUE; Open_helpwin(NumChar,X-1,Y-1); }
  438.                                 else window->Flags &= ~RMBTRAP;
  439.                                 IsDraw=NOT_PRESSED;
  440.                             }
  441.                             break;
  442.                         /* Clear the help window: */
  443.                         case MENUUP:
  444.                             window->Flags &= ~RMBTRAP;
  445.                             if(HelpWin) { HelpWin=FALSE; Close_helpwin(); goto CL; }
  446.                     }
  447.                     break;
  448.                         
  449.                 case MOUSEMOVE: if(IsDraw>0 && !HelpWin) Handle_box(); break;
  450.  
  451.                 case MENUPICK:
  452.                     Handle_menu( GTMENUITEM_USERDATA((struct MenuItem *) ItemAddress(menu,message.Code)) );
  453.                     break;
  454.  
  455.                 case RAWKEY:        /* Rawkey which will be Translated */
  456.                     /* If the rawkey code can be processed, don't translate it: */
  457.                     if(message.Code>127) break; Handle_keyboard(message.Code);
  458.  
  459.                     ie.ie_Code = message.Code;
  460.  
  461.                     /* Make sure deadkeys and qualifiers are take into account: */
  462.                     ie.ie_EventAddress = *((APTR *)message.IAddress);
  463.                     ie.ie_Qualifier = message.Qualifier;
  464.  
  465.                     /* Map RAWKEY to ANSI */
  466.                     if(MapRawKey(&ie, buffer, 8, NULL) <= 0) break;
  467. #                    define    code        PopWin
  468.                     code = *buffer;
  469.  
  470.                     /* Space bar inserts the highlighted char in the string gadget: */
  471.                     if(code==' ') goto INS;
  472.                      if(code==27 && IsDraw) goto CL;
  473.  
  474.                     /* ESC hide the interface, whilst SHIFT ESC, quit the programm: */
  475.                     if(code==27) cleanup(NULL,IconBase && !(ie.ie_Qualifier&IEQUALIFIER_LSHIFT)?-1:0);
  476.  
  477.                     /* Remove the last inputed char or clear all the string gadget: */
  478.                     if(code=='\b' || code==127) {
  479.                         register WORD n=(code=='\b'?sti(gad)->NumChars-1:0);
  480.                         if(n<0) break;
  481.                         StrBuf[n]=0;
  482.                         RefreshGList(gad, window, NULL, 1);
  483.                     }
  484.                     break;
  485.                 case GADGETUP:
  486.                     Handle_gadget( (struct Gadget *)message.IAddress );
  487.                     break;
  488.  
  489.                 case REFRESHWINDOW:
  490.                     /* A iconified window has been poped-up: */
  491.                     if(window->Height>window->BorderTop) Draw_ASCIIChart();
  492.             }
  493.             /* Has the user hiden the window ? */
  494.             if(window==NULL) goto Deb;
  495.         }
  496.     }
  497. }
  498.